<template>
  <el-color-picker
    v-model="theme"
    :predefine="[
      '#409EFF',
      '#1890ff',
      '#304156',
      '#212121',
      '#11a983',
      '#13c2c2',
      '#6959CD',
      '#f5222d',
    ]"
    class="theme-picker"
    popper-class="theme-picker-dropdown"
  />
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
import { useStore } from 'vuex'

// 定义组件名称
defineOptions({
  name: 'ThemePicker'
})

const ORIGINAL_THEME = '#409EFF' // default color

// 定义响应式数据
const chalk = ref('')
const theme = ref('')

// 获取 store 实例
const store = useStore()

// 计算属性
const defaultTheme = computed(() => {
  return store.state.settings.theme
})

// 监听器
watch(defaultTheme, (val) => {
  theme.value = val
}, { immediate: true })

watch(theme, async (val) => {
  if (typeof val === 'string') {
    await setTheme(val)
  }
})

// 生命周期钩子
onMounted(() => {
  if (defaultTheme.value !== ORIGINAL_THEME) {
    setTheme(defaultTheme.value)
  }
})

// 方法定义
const setTheme = async (val: string) => {
  const oldVal = chalk.value ? theme.value : ORIGINAL_THEME
  if (typeof val !== 'string') return
  const themeCluster = getThemeCluster(val.replace('#', ''))
  const originalCluster = getThemeCluster(oldVal.replace('#', ''))

  const getHandler = (variable: string, id: string) => {
    return () => {
      const originalCluster = getThemeCluster(ORIGINAL_THEME.replace('#', ''))
      const newStyle = updateStyle(variable === 'chalk' ? chalk.value : '', originalCluster, themeCluster)

      let styleTag = document.getElementById(id)
      if (!styleTag) {
        styleTag = document.createElement('style')
        styleTag.setAttribute('id', id)
        document.head.appendChild(styleTag)
      }
      if (styleTag) {
        styleTag.innerText = newStyle
      }
    }
  }

  if (!chalk.value) {
    const url = `/styles/theme-chalk/index.css`
    await getCSSString(url, 'chalk')
  }

  const chalkHandler = getHandler('chalk', 'chalk-style')
  chalkHandler()

  const styles = [].slice.call(document.querySelectorAll('style')).filter((style) => {
    const text = (style as HTMLElement).innerText
    return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
  }) as HTMLStyleElement[]
  
  styles.forEach((style) => {
    const { innerText } = style
    if (typeof innerText !== 'string') return
    style.innerText = updateStyle(innerText, originalCluster, themeCluster)
  })

  // 发送 change 事件
  emits('change', val)
}

const updateStyle = (style: string, oldCluster: string[], newCluster: string[]): string => {
  let newStyle = style
  oldCluster.forEach((color, index) => {
    // 确保 newCluster[index] 存在
    if (newCluster[index]) {
      newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
    }
  })
  return newStyle
}

const getCSSString = (url: string, variable: string): Promise<void> => {
  return new Promise((resolve) => {
    const xhr = new XMLHttpRequest()
    xhr.onreadystatechange = () => {
      if (xhr.readyState === 4 && xhr.status === 200) {
        if (variable === 'chalk') {
          chalk.value = xhr.responseText.replace(/@font-face{[^}]+}/, '')
        }
        resolve()
      }
    }
    xhr.open('GET', url)
    xhr.send()
  })
}

const getThemeCluster = (theme: string): string[] => {
  const tintColor = (color: string, tint: number): string => {
    let red: number | string = parseInt(color.slice(0, 2), 16)
    let green: number | string = parseInt(color.slice(2, 4), 16)
    let blue: number | string = parseInt(color.slice(4, 6), 16)

    if (tint === 0) {
      // when primary color is in its rgb space
      return [red, green, blue].join(',')
    } else {
      red += Math.round(tint * (255 - Number(red)))
      green += Math.round(tint * (255 - Number(green)))
      blue += Math.round(tint * (255 - Number(blue)))

      red = Number(red).toString(16)
      green = Number(green).toString(16)
      blue = Number(blue).toString(16)

      // 确保两位数
      red = red.padStart(2, '0')
      green = green.padStart(2, '0')
      blue = blue.padStart(2, '0')

      return `#${red}${green}${blue}`
    }
  }

  const shadeColor = (color: string, shade: number): string => {
    let red: number | string = parseInt(color.slice(0, 2), 16)
    let green: number | string = parseInt(color.slice(2, 4), 16)
    let blue: number | string = parseInt(color.slice(4, 6), 16)

    red = Math.round((1 - shade) * Number(red))
    green = Math.round((1 - shade) * Number(green))
    blue = Math.round((1 - shade) * Number(blue))

    red = Number(red).toString(16)
    green = Number(green).toString(16)
    blue = Number(blue).toString(16)

    // 确保两位数
    red = red.padStart(2, '0')
    green = green.padStart(2, '0')
    blue = blue.padStart(2, '0')

    return `#${red}${green}${blue}`
  }

  const clusters = [theme]
  for (let i = 0; i <= 9; i++) {
    clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
  }
  clusters.push(shadeColor(theme, 0.1))
  return clusters
}

// 定义事件发射
const emits = defineEmits<{
  (e: 'change', val: string): void
}>()
</script>

<style>
.theme-message,
.theme-picker-dropdown {
  z-index: 99999 !important;
}

.theme-picker .el-color-picker__trigger {
  height: 26px !important;
  width: 26px !important;
  padding: 2px;
}

.theme-picker-dropdown .el-color-dropdown__link-btn {
  display: none;
}
</style>